from django.http import HttpResponse, JsonResponse
import logging, json, uuid
# from collections import deque
import signal, random
# import time
import redis
from redis.lock import Lock
from django.views.decorators.csrf import csrf_exempt
# from demob.settings import USERS
# from threading import Lock
from django.core.cache import caches, cache as ca
# from django_redis import get_redis_connection
# from vay.tools.redis_lock import RedisLock

#redis_conn = get_redis_connection('default')
redis_conn = redis.Redis(host='localhost', port=6379, db=0)

userq_2_key = 'userq_2'
redis_conn.delete(userq_2_key)
redis_conn.rpush(userq_2_key, 'item1')
redis_conn.lpop(userq_2_key)
userq_3_key = 'userq_3'
redis_conn.delete(userq_3_key)
redis_conn.rpush(userq_3_key, 'item1')
redis_conn.lpop(userq_3_key)
userq_4_key = 'userq_4'
redis_conn.delete(userq_4_key)
redis_conn.rpush(userq_4_key, 'item1')
redis_conn.lpop(userq_4_key)

cache = caches['default']
cache_timout = 600

# 定义超时处理函数
# def timeout_handler(signum, frame):
#     print("Timeout!")
#     exit(0)

# 设置超时时间为5秒
# signal.signal(signal.SIGALRM, timeout_handler)
# signal.alarm(5)

logger = logging.getLogger('vay')

# USERS = {'123030930084': 'uuid'}
#USERS = {}
# cache.set('USERS', USERS)
#lock_users = Lock()
#lock_users = cache.lock("lock_users")

# USERS_DETAIL = {uuid: {}}
#USERS_DETAIL = {}

#lock_user_detail = Lock()
# lock_user_detail = cache.lock("lock_user_detail")
lock_user_detail =  Lock(redis_conn, 'lock_user_detail')

# GAMES = []
GAMES = {2: ['电影', '电视'], 3: ['斗地主', '蛋仔派对'], 4: ['四川麻将', '环城骑行']}

# GROUPS2 = {['123030930084', '123030930085']}
#USER_QUEUE = {2: deque(), 3: deque(), 4: deque()}
#cache.set("userq_2", deque())
# userq_2 = deque()
# userq_3 = deque()
# userq_4 = deque()
#cache.set("userq_3", deque())
#cache.set("userq_4", deque())

# lock_user_queue = Lock()
# lock_user_queue = cache.lock("lock_user_queue")
lock_user_queue =  Lock(redis_conn, 'lock_user_queue')

#GROUP_QUEUE = {2: deque(), 3: deque(), 4: deque()}
#lock_group_queue = Lock()
#GROUP2 = []

# GROUP_GAME = {gid: {'users': [], 'game': '电影', 'table': 1}}
#GROUP_GAME = {}
# cache.get(gid)
# lock_group_game = Lock()
# lock_group_game = cache.lock("lock_group_game")
lock_group_game = Lock(redis_conn, 'lock_group_game')

# GROUP_FULL = {gid: False}
#GROUP_FULL = {a}

# TEAM_CONFIRM = {gid: False}
#TEAM_CONFIRM = {}
# cache.set("confirm" + ntoa(gid), False)
# lock_confirm = Lock()
# lock_confirm = cache.lock("lock_confirm")
lock_confirm = Lock(redis_conn, 'lock_confirm')

def ntoa(n):
    return str(n)

# def fetch_cache():
#     data = []
#     cache = caches['default']
#     all_keys = cache.keys()
#     for c in all_keys:
#         data.append({c: cache.get(c)})
#     return data

def index(request):
    return HttpResponse("Hello, world. You're at the vay index.")

@csrf_exempt
def users(request):
    rsp = {'code': 200}
    body_unicode = request.body.decode('utf-8')
    body = json.loads(body_unicode)
    user_id = ntoa(body.get('user_id'))
    user_name = body.get('user_name')
    #lock_users.acquire()
    uid = cache.get(user_id)
    if not uid:
        logger.info("New user: %s:%s" % (user_id, user_name))
        uid = str(uuid.uuid4())
        cache.add(user_id, uid, timeout=600)
        cache.add(uid, {'usid': user_id, 'user_name': user_name, 'user_group': '', 'confirm': False, 'queued': False, 'table_count': 0}, timeout=600)
    #lock_users.release()
    logger.info(f'user login info: {body}')
    logger.info("User_id: %s" % cache.get(user_id))
    logger.info("UserInfo: %s" % cache.get(uid))
    print("User_id: %s" % cache.get(user_id))
    print("UserInfo: %s" % cache.get(uid))
    #print(fetch_cache())
    #print(USERS_DETAIL)
    return JsonResponse(rsp)

@csrf_exempt
def join(request):
    data = {'table_id': '', 'game_name': '', 'user_list': []}
    rsp = {"code": 200, "data": data}
    body_unicode = request.body.decode('utf-8')
    body = json.loads(body_unicode)
    user_id = ntoa(body.get('user_id'))
    table_count = int(body.get('table_count'))
    logger.info("Check users pre: %s" % cache.get(user_id))
    if not cache.get(user_id):
        rsp['code'] = 400
        rsp['message'] = "%s User do not create." % user_id
        return JsonResponse(rsp)
    uid = cache.get(user_id)
    if not cache.get(uid):
        rsp['code'] = 400
        rsp['message'] = "UserInfo %s is not exist." % uid
        return JsonResponse(rsp)
    # lock_user_detail.acquire()
    user_detail = cache.get(uid)
    #logger.info("Check user detail info: %s" % user_detail)
    # 用户已经有组，获取组信息
    if user_detail['user_group'] != '':
        # lock_user_detail.release()
        gid = user_detail['user_group']
        logger.info("[join] User had been put in group: %s" % gid)
        gpinfo = cache.get(gid)
        if not gpinfo:
            rsp['code'] = 201
            rsp['message'] = "[join] Group %s no create." % gid
            return JsonResponse(rsp)
        logger.info("Group info for user %s is: %s" % (user_id, gpinfo))
        if table_count != user_detail['table_count'] and user_detail['table_count'] != 0:
            rsp['code'] = 400
            rsp['message'] = "[join] You have been in a group(%s owners)" % len(gpinfo['users'])
            return JsonResponse(rsp)
        table_id = gpinfo['table']
        game_name = gpinfo['game']
        #user_list = gpinfo['users']
        ut = []
        for u in gpinfo['users']:
            ud = cache.get(u)
            ut.append({'user_id': ud['usid'], 'user_name': ud['user_name']})
        data['table_id'] = table_id
        data['game_name'] = game_name
        data['user_list'] = ut
        rsp['data'] = data
        return JsonResponse(rsp)
    userq_key = "userq_" + ntoa(table_count)
    userq_len = redis_conn.llen(userq_key)
    logger.info("[%s] Check user queue %s length: %d" % (user_id, userq_key, userq_len))

    counti = table_count

    if not user_detail['queued']:
        counti = counti - 1

    if userq_len < counti:
        # 将用户加入用户队列中
        if not user_detail['queued']:
            f = False
            lock_user_queue.acquire()
            if not user_detail['queued']:
                redis_conn.rpush(userq_key, uid)
                user_detail['queued'] = True
                user_detail['table_count'] = table_count
                f = True
                cache.set(uid, user_detail, timeout=cache_timout)
                #cache.set("userq_" + ntoa(table_count), userq)
            lock_user_queue.release()
            if f:
                logger.info("User %s enqueued" % user_id)
        
        rsp['code'] = 201
        rsp['message'] = "Don't hvae enough users to form a team."
        return JsonResponse(rsp)
    # 用户没有组，但用户队列中有足够的用户可用，为用户组建一个组
    # if userq_len >= counti:
    else:
        logger.info("队列够长，给用户%s分配组" % user_id)
        gid = str(uuid.uuid4())
        ginfo = {}
        ginfo['table'] = random.randint(1, 100)
        w = len(GAMES[table_count]) - 1
        ginfo['game'] = GAMES[table_count][random.randint(0, w)]
        ginfo['users'] = [uid]
        user_detail['user_group'] = gid
        user_detail['table_count'] = table_count
        cache.set(uid, user_detail, timeout=cache_timout)
        confirm_key = "confirm" + ntoa(gid)
        if lock_confirm.acquire():
            try:
                cache.set(confirm_key, False, timeout=cache_timout)
            finally:
                lock_confirm.release()
        popc = table_count - 1
        while popc != 0:
            logger.info("[join: %s]当前队列长度: %d" % (user_id, redis_conn.llen(userq_key)))
            # if redis_conn.llen(userq_key) == 0:
            #     rsp['code'] = 201
            #     rsp['message'] = "No user enough."
            #     logger.info("[join: %s] No user enough." % (user_id))
            #     return JsonResponse(rsp)
            u = str(redis_conn.lpop(userq_key).decode('utf-8'))
            detailu = cache.get(u)
            if not detailu:
                logger.info("[join] 用户详情%s不存在" % u)
                continue
            if detailu['table_count'] != table_count:
                logger.info("[join: %s] 记录的组人数: %d, 但是当前给的组人数: %d" % (detailu['usid'], detailu['table_count'], table_count))
                continue
            if detailu['user_group'] != '':
                if redis_conn.llen(userq_key) < table_count - len(ginfo['users']) :
                    rsp['code'] = 201
                    rsp['message'] = "Don't hvae enough users: %d to form a team." % table_count
                    return JsonResponse(rsp)
                logger.info("[join: %s] 待分配用户已经有组了" % (detailu['usid']))
                continue
            if u == uid:
                logger.info("[join: %s] 取出的用户即当前请求用户" % (detailu['usid']))
                continue
            ginfo['users'].append(u)
            logger.info("现在将用户%s添加到组%s" % (u, gid))
            logger.info("该用户信息为: %s" % detailu)
            detailu['user_group'] = gid
            cache.set(u, detailu, timeout=cache_timout)
            popc = popc - 1
        cache.set(gid, ginfo, timeout=cache_timout)
        # lock_user_detail.release()
        data['table_id'] = ginfo['table']
        data['game_name'] = ginfo['game']
        usl = []
        for u in ginfo['users']:
            ud = cache.get(u)
            usl.append({'user_id': ud['usid'], 'user_name': ud['user_name']})
        data['user_list'] = usl
        rsp['data'] = data
        return JsonResponse(rsp)

    # lock_user_detail.release()

    # 等待用户被其他人添加到组，并取出组信息
    # 逻辑修改，用户不再等待，没有足数的队友，返回201
    # c = 60
    # while True:
    #     if cache.get(uid)['user_group'] == '':
    #         if c == 0:
    #             break
    #         time.sleep(1)
    #         c = c - 1
    #         continue
    #     gid = cache.get(uid)['user_group']
    #     group_info = cache.get(gid)
    #     data['table_id'] = group_info['table']
    #     data['game_name'] = group_info['game']
    #     usl = []
    #     for u in group_info['users']:
    #         ud = cache.get(u)
    #         usl.append({'user_id': ud['usid'], 'user_name': ud['user_name']})
    #     data['user_list'] = usl
    #     rsp['data'] = data
    #     return JsonResponse(rsp)
    


@csrf_exempt
def cancel(request):
    rsp = {"code": 200}
    body_unicode = request.body.decode('utf-8')
    body = json.loads(body_unicode)
    user_id = ntoa(body.get('user_id'))
    uid = cache.get(user_id)
    table = int(body.get('table_id'))

    if not cache.get(user_id):
        rsp['message'] = "User %s not exist" % user_id
        return JsonResponse(rsp)
    user_info = cache.get(uid)
    gid = user_info['user_group']
    if not cache.get(gid):
        return JsonResponse(rsp)
    group_info = cache.get(gid)
 
    confirm_key = "confirm" + ntoa(gid)
    # 如果所有用户已经确认，不允许取消
    if cache.get(confirm_key):
        rsp['code'] = 400
        rsp['message'] = "All users in group has confirmed, DO NOT CANCEL!"
        logger.info("[join] [user: %s] All users in group %s has confirmed, DO NOT CANCEL!" % (user_id, gid))
        return JsonResponse(rsp)
    # 删除确认键
    cache.delete(confirm_key)
    # 重置用户详细信息
    for usid in group_info['users']:
        userif = cache.get(usid)
        logger.info("需要重置的用户信息是%s: %s" % (usid, userif))
        if userif:
            userif['user_group'] = ''
            userif['confirm'] = False
            userif['queued'] = False
            userif['table_count'] = 0
            cache.set(usid, userif, timeout=cache_timout)
            logger.info("[cancel] 重置后的用户信息是%s: %s" % (usid, userif))
    # 删除组
    if cache.get(gid):
        cache.delete(gid)

    return JsonResponse(rsp)

@csrf_exempt
def confirm(request):
    rsp = {"code": 200}
    body_unicode = request.body.decode('utf-8')
    body = json.loads(body_unicode)
    user_id = ntoa(body.get('user_id'))
    uid = cache.get(user_id)
    table = int(body.get('table_id'))
    user_info = cache.get(uid)
    if not user_info:
        rsp['code'] = 400
        rsp['message'] = "User do not create."
        return JsonResponse(rsp)
    gid = user_info['user_group']
    if gid == '':
        rsp['code'] = 201
        return JsonResponse(rsp)
    group_info = cache.get(gid)
    confirm_key = "confirm" + ntoa(gid)
    user_info['confirm'] = True
    cache.set(uid, user_info, timeout=cache_timout)
    logger.info("[confirm] Commit to confirm for user %s" % user_id)
    print(group_info, cache.get(confirm_key))

    if cache.get(confirm_key):
        return JsonResponse(rsp)
    
    check_users_confirm = True
    for u in group_info['users']:
        if not cache.get(u)['confirm']:
            check_users_confirm = False
            break
    
    if check_users_confirm:
        if lock_confirm.acquire():
            try:
                cache.set(confirm_key, True, timeout=cache_timout)
            finally:
                lock_confirm.release()
        return JsonResponse(rsp)

    #if cache.get(confirm_key):
    #    return JsonResponse(rsp)
    # c = 60
    # while True:
    #     if cache.get(confirm_key):
    #         return JsonResponse(rsp)
    #     if c == 0:
    #         break
    #     time.sleep(1)
    #     c = c - 1
    
    # rsp['code'] = 400
    # rsp['message'] = "Timeout for waiting others' confirm."
    rsp['code'] = 201
    return JsonResponse(rsp)
